package com.xigege.netty.dubborpc.netty;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.concurrent.Callable;
//调用顺序：channelActive->setPara->call->channelRead->call
public class NettyClientHandler extends ChannelInboundHandlerAdapter implements Callable {
    //上下文
    private ChannelHandlerContext context;
    //返回的结果
    private String result;
    //客户端调用方法时，传入的参数
    private String para;

    //与服务器连接创建成功后，就会被调用，所以这个方法是第一个被调用的
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelActive 被调用");
        //因为在其他方法也会使用到这个ctx
        context = ctx;
    }

    //收到服务器的数据后就会调用方法
    @Override
    //channelRead和call是有一个同步关系的，加上一个synchronized关键字
    public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println(" channelRead 被调用  ");
        result = msg.toString();

        //唤醒等待的线程
        //客户端的handler(就是本类)中有一个call方法，调用方法时，是先通过这个call调用方法把数据发送给服务器端
        //这个方法是通过反射机制来调用的，调用完之后返回的数据并没有马上回来，所以在call里面会让这个方法进行一个wait
        //基于netty，服务器端回送的信息其实是回送到handler的channelRead方法
        //代理对象调用的call，call方法发送数据之后，就在原地等待着返回数据的回来，但是返回数据到了channelRead中
        //所以这里需要一个notify唤醒的操作，代码才能继续往下执行
        //现在这个结果已经给到本方法（channelRead）的result中了，再通过call把结果返回给代理对象
        notify();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }

    //被代理对象调用，发送数据给服务器，发送完后就进入wait状态，等待被channelRead唤醒，唤醒后才能返回结果
    @Override
    public synchronized Object call() throws Exception {
        System.out.println(" call1 被调用  ");
        context.writeAndFlush(para);
        //进行wait，等待channelRead获取到服务器的结果后，唤醒我
        wait();
        //服务方返回的结果
        return result;
    }

    void setPara(String para) {
        this.para = para;
    }
}
